/**
 * Event Service - Centralized event management for Electron IPC communication
 *
 * Provides type-safe event emission and handling between main and renderer processes.
 * Supports both broadcast (all windows) and targeted (specific thread) messaging.
 *
 * Event Flow:
 * - Main-to-Main: Direct mitt-based event emission within main process
 * - Main-to-Renderer: IPC-based events sent to browser windows
 * - Thread-specific: Events targeted to specific conversation threads
 */

import type {
  Language,
  Message,
  Provider,
  ShortcutAction,
  Tab,
  UpdateProviderData,
} from "@shared/triplit/types";
import type { ContentBlock } from "@shared/types/sequential-content";
import type { UpdaterStatus } from "@shared/types/version-updater";
import { BrowserWindow } from "electron";
import mitt from "mitt";

export enum RendererTarget {
  ALL_WINDOWS = "all-windows",
  THREAD = "thread",
}

export enum EventNames {
  // Provider lifecycle events
  PROVIDER_ADD = "provider:add",
  PROVIDER_DELETE = "provider:delete",
  PROVIDER_UPDATE = "provider:update",

  PROVIDER_CONVERSATION_CREATED = "provider:conversation-created",
  PROVIDER_CONVERSATION_IN_PROGRESS = "provider:conversation-in-progress",
  PROVIDER_CONVERSATION_COMPLETED = "provider:conversation-completed",
  PROVIDER_CONVERSATION_FAILED = "provider:conversation-failed",
  PROVIDER_CONVERSATION_EXPIRED = "provider:conversation-expired",
  PROVIDER_CONVERSATION_CANCELLED = "provider:conversation-cancelled",

  // Chat and messaging events
  CHAT_STREAM_STATUS_UPDATE = "chat:stream-status-update",
  MESSAGE_ACTIONS = "message:actions",
  MESSAGE_SEND_FROM_USER = "message:send-from-user",

  // Window management events
  WINDOW_TITLE_BAR_OVERLAY_UPDATE = "window:title-bar-overlay-update",
  WINDOW_MAC_FULLSCREEN_STATE_UPDATE = "window:mac-maximized-state-update",

  // Application events
  SHORTCUT_TRIGGERED = "shortcut:triggered",
  UPDATER_CHECK_STATUS = "updater:check-status",
  SETTINGS_LANGUAGE_UPDATE = "settings:language-update",

  // Thread events
  THREAD_CREATED = "thread:created",
  THREAD_RENAME = "thread:title-rename",
  THREAD_DELETED = "thread:deleted",
  THREAD_DELETED_ALL = "thread:deleted-all",
  THREAD_NEW_BRANCH = "thread-new-branch",

  // MCP tool execution events
  TOOL_CALL_START = "tool-call:start",
  TOOL_CALL_SUCCESS = "tool-call:success",
  TOOL_CALL_ERROR = "tool-call:error",
  TOOL_CALL_COMPLETE = "tool-call:complete",

  // MCP tool approval events
  TOOL_CALL_APPROVAL_REQUIRED = "tool-call:approval-required",
  TOOL_CALL_APPROVED = "tool-call:approved",
  TOOL_CALL_REJECTED = "tool-call:rejected",

  // MCP reflection-action workflow events
  MCP_REFLECTION_START = "mcp-reflection:start",
  MCP_REFLECTION_CONTENT = "mcp-reflection:content",
  MCP_ACTION_PHASE = "mcp-action:phase",
  CONTENT_BLOCK_ADD = "content-block:add",
  CONTENT_BLOCK_UPDATE = "content-block:update",
  SEQUENTIAL_CONTENT_COMPLETE = "sequential-content:complete",

  // Tab events
  TAB_SWITCHED = "tab:switched",
  TAB_CLOSED = "tab:closed",

  // System events
  TRI_SERVER_INIT_COMPLETED = "triplit:server-init-completed",

  // Message events
  MESSAGE_RENDERED = "message:rendered",

  SYSTEM_PROMPT_RENDERED = "system-prompt-rendered",
}

export type Events = {
  [EventNames.PROVIDER_ADD]: {
    provider: Provider;
  };
  [EventNames.PROVIDER_DELETE]: {
    providerId: string;
  };
  [EventNames.PROVIDER_UPDATE]: {
    providerId: string;
    updateData: UpdateProviderData;
  };

  [EventNames.PROVIDER_CONVERSATION_CREATED]: {
    threadId: string;
  };
  [EventNames.PROVIDER_CONVERSATION_IN_PROGRESS]: {
    threadId: string;
    delta?: string;
  };
  [EventNames.PROVIDER_CONVERSATION_COMPLETED]: {
    threadId: string;
    regeneration: boolean;
  };
  [EventNames.PROVIDER_CONVERSATION_FAILED]: {
    threadId: string;
  };
  [EventNames.PROVIDER_CONVERSATION_EXPIRED]: {
    threadId: string;
  };
  [EventNames.PROVIDER_CONVERSATION_CANCELLED]: {
    threadId: string;
  };

  [EventNames.CHAT_STREAM_STATUS_UPDATE]: {
    threadId: string;
    status: "pending" | "success" | "error" | "stop" | "initializing";
    delta?: string;
    userMessageId?: string;
  };
  [EventNames.MESSAGE_ACTIONS]: {
    threadId: string;
    actions: {
      type: "edit" | "delete" | "delete-single";
      message?: Message;
      messages?: Message[];
    };
  };
  [EventNames.MESSAGE_SEND_FROM_USER]: {
    threadId: string;
    selectedMcpServerIds?: string[];
  };
  [EventNames.WINDOW_TITLE_BAR_OVERLAY_UPDATE]: null;
  [EventNames.WINDOW_MAC_FULLSCREEN_STATE_UPDATE]: {
    isMaximized: boolean;
  };
  [EventNames.SHORTCUT_TRIGGERED]: {
    action: ShortcutAction;
  };
  [EventNames.UPDATER_CHECK_STATUS]: {
    status: UpdaterStatus;
    version?: string;
    precent?: number;
  };
  [EventNames.SETTINGS_LANGUAGE_UPDATE]: {
    language: Language;
  };

  [EventNames.THREAD_CREATED]: {
    triggerBy: "first-send-message" | "without-send-message";
    threadId: string;
  };
  [EventNames.THREAD_RENAME]: {
    threadId: string;
    newTitle: string;
  };
  [EventNames.THREAD_DELETED]: {
    threadId: string;
  };
  [EventNames.THREAD_DELETED_ALL]: null;
  [EventNames.THREAD_NEW_BRANCH]: {
    title: string;
    originalThreadId: string;
    newThreadId: string;
    type: Tab["type"];
    isPrivate: boolean;
    messageId: string;
    isNewTab?: boolean;
  };

  [EventNames.TAB_SWITCHED]: {
    previousTabId?: string;
    currentTabId: string;
  };
  [EventNames.TAB_CLOSED]: {
    tabId: string;
  };

  [EventNames.TOOL_CALL_START]: {
    threadId: string;
    messageId: string;
    toolCallId: string;
    toolName: string;
  };
  [EventNames.TOOL_CALL_SUCCESS]: {
    threadId: string;
    messageId: string;
    toolCallId: string;
    toolName: string;
    result: string;
    executionTime: number;
  };
  [EventNames.TOOL_CALL_ERROR]: {
    threadId: string;
    messageId: string;
    toolCallId: string;
    toolName: string;
    error: string;
  };
  [EventNames.TOOL_CALL_COMPLETE]: {
    threadId: string;
    messageId: string;
    completedCalls: number;
    totalCalls: number;
  };

  // * MCP Tool Approval Events
  [EventNames.TOOL_CALL_APPROVAL_REQUIRED]: {
    threadId: string;
    messageId: string;
    toolCallId: string;
    toolName: string;
    toolArguments: string;
    mcpServerId: string;
  };
  [EventNames.TOOL_CALL_APPROVED]: {
    threadId: string;
    messageId: string;
    toolCallId: string;
  };
  [EventNames.TOOL_CALL_REJECTED]: {
    threadId: string;
    messageId: string;
    toolCallId: string;
    reason?: string;
  };

  // * MCP Reflection-Action Events
  [EventNames.MCP_REFLECTION_START]: {
    threadId: string;
    messageId: string;
    blockId: string;
  };
  [EventNames.MCP_REFLECTION_CONTENT]: {
    threadId: string;
    messageId: string;
    blockId: string;
    content: string;
    isComplete: boolean;
  };
  [EventNames.MCP_ACTION_PHASE]: {
    threadId: string;
    messageId: string;
    phase: "starting" | "executing" | "completed";
  };
  [EventNames.CONTENT_BLOCK_ADD]: {
    threadId: string;
    messageId: string;
    blockId: string;
    blockType?: "reflection" | "tool_call"; // Optional for backward compatibility
    order?: number; // Optional for backward compatibility
    block?: ContentBlock; // The complete block data for real-time updates
  };
  [EventNames.CONTENT_BLOCK_UPDATE]: {
    threadId: string;
    messageId: string;
    blockId: string;
    updateData: Record<string, unknown>;
  };
  [EventNames.SEQUENTIAL_CONTENT_COMPLETE]: {
    threadId: string;
    messageId: string;
    totalBlocks: number;
  };

  [EventNames.TRI_SERVER_INIT_COMPLETED]: null;

  [EventNames.MESSAGE_RENDERED]: {
    messageId: string;
    template: string;
    renderedContent: string;
    variables: string[];
    renderMap: Record<string, string>;
  };

  [EventNames.SYSTEM_PROMPT_RENDERED]: {
    threadId: string;
    renderMap: Record<string, string>;
    variables: string[];
    renderedContent: string;
  };
};

const oriMittInstance = mitt<Events>();

export const emitter = {
  ...oriMittInstance,
  on<Key extends keyof Events>(
    type: Key,
    handler: (event: Events[Key]) => void,
  ): () => void {
    oriMittInstance.on(type, handler);
    return () => oriMittInstance.off(type, handler);
  },
  // Original mitt instance
  _mittInstance: oriMittInstance,
};

export function sendToMain(type: keyof Events, data: Events[keyof Events]) {
  emitter.emit(type, data);
}

export function sendToRenderer(
  type: keyof Events,
  data: Events[keyof Events],
  target: RendererTarget = RendererTarget.ALL_WINDOWS,
  threadId?: string,
) {
  switch (target) {
    case RendererTarget.ALL_WINDOWS:
      sendToAllWindows(type, data);
      break;
    case RendererTarget.THREAD:
      if (!threadId) return;
      sendToThread(threadId, type, data);
      break;
    default:
      sendToAllWindows(type, data);
      break;
  }
}

export function sendToThread(
  threadId: string,
  type: keyof Events,
  data: Events[keyof Events],
) {
  BrowserWindow.getAllWindows().forEach((window) => {
    window.webContents.send(`${type}-${threadId}`, data);
  });
}

function sendToAllWindows(type: keyof Events, data: Events[keyof Events]) {
  BrowserWindow.getAllWindows().forEach((window) => {
    window.webContents.send(type, data);
  });
}
